package store

import (
	"encoding/json"
	"fmt"
	"io"
	"path/filepath"
	"sync"
	"time"

	"github.com/hashicorp/raft"
	boltdb "github.com/hashicorp/raft-boltdb"
)

// Store 定义了存储接口
type Store interface {
	// 保存数据到存储
	Set(key, value string) error
	// 从存储获取数据
	Get(key string) (string, error)
	// 关闭存储
	Close() error
}

// BoltStore 实现了基于 BoltDB 的存储
type BoltStore struct {
	raft *raft.Raft // 保持为私有字段
	mut  sync.RWMutex
}

// NewBoltStore 创建一个新的 BoltStore 实例
func NewBoltStore() *BoltStore {
	return &BoltStore{}
}

// SetRaft 设置 Raft 实例（添加这个方法来解决访问私有字段的问题）
func (s *BoltStore) SetRaft(r *raft.Raft) {
	s.raft = r
}

// Set 设置键值对
func (s *BoltStore) Set(key, value string) error {
	s.mut.Lock()
	defer s.mut.Unlock()

	if s.raft == nil {
		return fmt.Errorf("raft is not initialized")
	}

	cmd := &Command{Type: "set", Key: key, Value: value}
	buf, err := json.Marshal(cmd)
	if err != nil {
		return err
	}

	future := s.raft.Apply(buf, 500*time.Millisecond)
	if err := future.Error(); err != nil {
		return err
	}

	return nil
}

// Get 获取键值对
func (s *BoltStore) Get(key string) (string, error) {
	s.mut.RLock()
	defer s.mut.RUnlock()

	// 在实际应用中，这里应该从本地缓存或直接从 BoltDB 中读取数据
	// 为了简化示例，我们返回空值
	return "", fmt.Errorf("get not implemented in this example")
}

// Close 关闭存储
func (s *BoltStore) Close() error {
	return nil
}

// Command 定义了 Raft 命令的结构
type Command struct {
	Type  string `json:"type"`
	Key   string `json:"key"`
	Value string `json:"value"`
}

// FSM 实现了 Raft 的有限状态机接口
type FSM struct {
	store *BoltStore // 保持为私有字段
}

// NewFSM 创建一个新的 FSM 实例（添加这个构造函数来解决访问私有字段的问题）
func NewFSM(store *BoltStore) *FSM {
	return &FSM{store: store}
}

// Apply 应用 Raft 日志到状态机
func (f *FSM) Apply(log *raft.Log) interface{} {
	var cmd Command
	if err := json.Unmarshal(log.Data, &cmd); err != nil {
		return err
	}

	switch cmd.Type {
	case "set":
		// 在实际应用中，这里应该更新本地存储
		return nil
	default:
		return fmt.Errorf("unknown command type: %s", cmd.Type)
	}
}

// Snapshot 创建状态机快照
func (f *FSM) Snapshot() (raft.FSMSnapshot, error) {
	return &Snapshot{}, nil
}

// Restore 从快照恢复状态机
func (f *FSM) Restore(rc io.ReadCloser) error {
	defer rc.Close()
	// 在实际应用中，这里应该从快照中恢复数据
	return nil
}

// Snapshot 实现了 Raft 的快照接口
type Snapshot struct{}

// Persist 将快照持久化到输出流
func (s *Snapshot) Persist(sink raft.SnapshotSink) error {
	// 在实际应用中，这里应该将当前状态写入到 sink
	sink.Close()
	return nil
}

// Release 释放快照资源
func (s *Snapshot) Release() {
	// 释放任何与快照相关的资源
}

// NewRaftConfig 创建一个默认的 Raft 配置
func NewRaftConfig() *raft.Config {
	config := raft.DefaultConfig()
	config.LocalID = raft.ServerID("1")
	return config
}

// NewRaft 创建并配置一个新的 Raft 实例
func NewRaft(config *raft.Config, fsm raft.FSM, logs raft.LogStore, stable raft.StableStore, snaps raft.SnapshotStore, transport raft.Transport) (*raft.Raft, error) {
	return raft.NewRaft(config, fsm, logs, stable, snaps, transport)
}

// NewBoltStoreWithPath 创建一个新的 BoltDB 存储实例
func NewBoltStoreWithPath(dataDir string) (*boltdb.BoltStore, error) {
	store, err := boltdb.NewBoltStore(filepath.Join(dataDir, "raft.db"))
	if err != nil {
		return nil, fmt.Errorf("failed to create bolt store: %w", err)
	}
	return store, nil
}

// NewBoltStoreWithPathAndName 创建一个具有指定名称的 BoltDB 存储实例
func NewBoltStoreWithPathAndName(dataDir, fileName string) (*boltdb.BoltStore, error) {
	store, err := boltdb.NewBoltStore(filepath.Join(dataDir, fileName))
	if err != nil {
		return nil, fmt.Errorf("failed to create bolt store: %w", err)
	}
	return store, nil
}
